#include "AI.h"
#include <QDebug>
#include <QThread>

AI::AI()
{
    paraUpload();
}

AI::~AI()
{

}

void AI::setRoot(int *map, bool this_color, int prev_x, int prev_y)
{
    cout << prev_x << " " << prev_y << endl;
    rootNode = new Node(NULL, prev_x, prev_y);
    for (int i = 0; i < MAP_SIZE * MAP_SIZE; i++)
    {
        cout << map[i];
        if ((i + 1) % MAP_SIZE == 0)
            cout << endl;
        else
            cout << " ";
    }
    copy(map, rootNode->map);
    delete map;
    rootNode->nextColor = this_color ? WHITE : BLACK;
    qDebug()<<"from setRoot:" << QThread::currentThreadId();
    MCTS();
}

void AI::copy(int src[], int aim[])
{
    for (int i = 0; i < MAP_SIZE * MAP_SIZE; i++)
        aim[i] = src[i];
}

int AI::indexOf(Node *root, int index)
{
    for (int i = 0; i < (int)root->nextPos.size(); i++)
        if (root->nextPos[i] == index)
            return i;
    return -1;
}

void AI::copy(Node *src, Node *aim)
{
    copy(src->map, aim->map);
    aim->reward = src->reward;
    aim->visNum = src->visNum;
    aim->nextColor = src->nextColor;
    for (int i = 0; i < (int)src->nextAddr.size(); i++)
    {
        aim->nextAddr[i] = src->nextAddr[i];
        aim->nextPos[i] = src->nextPos[i];
    }
}

double AI::getProbability(int x, int y)
{
    return t_out[x * MAP_SIZE + y];
}

void AI::setProbability(int in[])
{
    for (int i = 0; i < HIDDEN; i++)
    {
        _out[i] = 0;
        for (int j = 0; j < FEATURE; j++)
        {
            _out[i] += (double)in[j] * v[i][j];
        }
        _out[i] += v_b[i];
        _out[i] = (double)1 / (double(1 + exp(-_out[i])));
    }
    for (int i = 0; i < OUTPUT; i++)
    {
        t_out[i] = 0;
        for (int j = 0; j < HIDDEN; j++)
        {
            t_out[i] += _out[j] * w[i][j];
        }
        t_out[i] += w_b[i];
        t_out[i] = (double)1 / (double(1 + exp(-t_out[i])));
    }
}

void AI::paraUpload()
{
    FILE *wp = fopen("nettest/ww.txt", "r");
    FILE *vp = fopen("nettest/vv.txt", "r");
    FILE *vb = fopen("nettest/v_b.txt", "r");
    FILE *wb = fopen("nettest/w_b.txt", "r");
    if (wp == NULL || vp == NULL || vb == NULL || wb == NULL)
    {
        cout << "files open false";
        exit(0);
    }
    double temp;
    int i = 0, j = 0;
    while (fscanf(vp, "%lf", &temp) != EOF)
    {
        v[i][j] = temp;
        j++;
        if (j == 225)
        {
            j = 0;
            i++;
        }
    }
    i = 0;
    j = 0;
    while (fscanf(wp, "%lf", &temp) != EOF)
    {
        w[i][j] = temp;
        j++;
        if (j == 30)
        {
            j = 0;
            i++;
        }
    }
    i = 0;
    while (fscanf(vb, "%lf", &temp) != EOF)
    {
        v_b[i++] = temp;
    }
    i = 0;
    while (fscanf(wb, "%lf", &temp) != EOF)
    {
        w_b[i++] = temp;
    }
    fclose(wp);
    fclose(vp);
    fclose(vb);
    fclose(wb);
}

int AI::getResult(Node *root)
{
    //还未结束时，返回0
    if (isTerminal(root) == false)
        return 0;
    /*for (int i = 0; i < MAP_SIZE * MAP_SIZE; i++)
    {
        cout << root->map[i];
        if ((i + 1) % MAP_SIZE == 0)
            cout << endl;
        else
            cout << " ";
    }*/

    //返回1，代表赢
    if (win)
        return 1;
    return 0;
}

Node *AI::bestChild(Node *root, double Constant = sqrt(2))
{
    setProbability(root->map);
    double maxUCT = -999999999;
    double maxChance = -1;
    Node *bestNode = NULL;
    for (int i = 0; i < (int)root->nextAddr.size(); i++)
    {
        Node *son = root->nextAddr[i];
        //UCT公式
        double left = (double)son->reward / (double)son->visNum;
        double right = Constant * sqrt(log(root->visNum) / (double)son->visNum);
        double tempUCT = left + right;
        //选取最好的结点
        if (tempUCT > maxUCT)
        {
            maxUCT = tempUCT;
            maxChance = getProbability(son->x, son->y);
            bestNode = son;
        }
        else if (tempUCT == maxUCT)
        {
            double chance = getProbability(son->x, son->y);
            if (chance > maxChance)
            {
                maxChance = chance;
                bestNode = son;
            }
        }
    }
    return bestNode;
}

Node *AI::expand(Node *root, int x, int y)
{
    //创建新结点
    Node *temp = new Node(root, x, y);
    copy(root->map, temp->map);
    temp->map[x * MAP_SIZE + y] = root->nextColor;
    //结点基本属性设置
    temp->nextColor = root->nextColor * -1;
    //将子结点加入父结点的子结点列表
    root->nextPos.push_back(x * MAP_SIZE + y);
    root->nextAddr.push_back(temp);
    return temp;
}

Node *AI::treePolicy(Node *root)
{
    //选择并扩展结点
    while (isTerminal(root) == false)
    {
        //cout << "Now: " << root->x << " " << root->y << endl;
        //当本结点存在棋盘上未访问结点时，访问之
        for (int row = 0; row < MAP_SIZE; row++)
            for (int col = 0; col < MAP_SIZE; col++)
                if (root->map[row * MAP_SIZE + col] == EMPTY && indexOf(root, row * MAP_SIZE + col) == -1)
                    return expand(root, row, col);
        //若该棋盘上其他结点全部被访问，从子结点中选最好结点
        root = bestChild(root);
        //cout << "best child: " << root->x << " " << root->y << endl;
    }
    return root;
}

int AI::defaultPolicy(Node *root)
{
    //模拟
    while (isTerminal(root) == false && root->nextPos.size() >= 1)
    {
        double maxProbability = -1;
        Node *ans = NULL;
        setProbability(root->map);
        for (int i = 0; i < (int)root->nextAddr.size(); i++)
        {
            Node *son = root->nextAddr[i];
            double temp = getProbability(son->x, son->y);
            if (maxProbability < temp)
            {
                maxProbability = temp;
                ans = son;
            }
        }
        root = ans;
    }
    //获得收益值，后续用来计算UCT
    return getResult(root);
}

void AI::backPropagation(Node *node, int reward)
{
    //回溯，将子节点收益和访问次数回传
    node->visNum++;
    node->reward += reward;
    if (node->parent != NULL)
        backPropagation(node->parent, reward * -1);
}

void AI::deleteTree(Node *root)
{
    if (root == NULL)
        return;
    for (int i = 0; i < (int)root->nextAddr.size(); i++)
        deleteTree(root->nextAddr[i]);
    delete root;
}

void AI::MCTS()
{
    //蒙特卡洛主干
    //开始搜索
    while (rootNode->visNum <= BUDGET)
    {
        //选择,拓展
        Node *node = treePolicy(rootNode);
        //模拟
        int reward = defaultPolicy(node);
        //回溯
        backPropagation(node, reward);
    }
    Node *pred = bestChild(rootNode, 0);
    //cout << pred->x << " " << pred->y << endl;
    emit sendPredict(pred->x, pred->y);
    delete (rootNode);
}


bool AI::isTerminal(Node *root)
{
    //获得x，y
    int x = root->x;
    int y = root->y;
    //行，列，主对角线，次对角线判断，满足任一条件则true
    win = rowJudge(root->map, x, y) || colJudge(root->map, x, y) || mainDiagonal(root->map, x, y) || subDiagonal(root->map, x, y);
    return drawJudge(root->map) || win;
}

bool AI::drawJudge(int map[])
{
    int count = 0;
    for (int i = 0; i < MAP_SIZE * MAP_SIZE; i++)
        if (map[i] == 0)
            count++;
    if (count == 0)
        return true;
    else
        return false;
}

bool AI::rowJudge(int map[], int x, int y)
{
    //行内判断
    int color = map[x * MAP_SIZE + y];
    int count = 1;
    while (y > 0 && map[x * MAP_SIZE + y - 1] == color)
        y--;
    while (y < MAP_SIZE - 1 && map[x * MAP_SIZE + y + 1] == color)
    {
        y++;
        count++;
    }
    if (count == WIN_LEN)
        return true;
    else
        return false;
}

bool AI::colJudge(int map[], int x, int y)
{
    //列内判断
    int color = map[x * MAP_SIZE + y];
    int count = 1;
    while (x > 0 && map[(x - 1) * MAP_SIZE + y] == color)
        x--;
    while (x < MAP_SIZE - 1 && map[(x + 1) * MAP_SIZE + y] == color)
    {
        x++;
        count++;
    }
    if (count == WIN_LEN)
        return true;
    else
        return false;
}

bool AI::mainDiagonal(int map[], int x, int y)
{
    //主对角线判断
    int color = map[x * MAP_SIZE + y];
    while (x > 0 && y > 0 && map[(x - 1) * MAP_SIZE + y - 1] == color)
    {
        x--;
        y--;
    }
    int count = 1;
    while (x < MAP_SIZE - 1 && y < MAP_SIZE - 1 && map[(x + 1) * MAP_SIZE + y + 1] == color)
    {
        x++;
        y++;
        count++;
    }
    if (count == WIN_LEN)
        return true;
    else
        return false;
}

bool AI::subDiagonal(int map[], int x, int y)
{
    //次对角线判断
    int color = map[x * MAP_SIZE + y];
    int count = 1;
    int row;
    int col;
    row = x;
    col = y;
    while (row < MAP_SIZE - 1 && col > 0 && map[(row + 1) * MAP_SIZE + col - 1] == color)
    {
        row++;
        col--;
        count++;
    }
    row = x;
    col = y;
    while (row > 0 && col < MAP_SIZE - 1 && map[(row - 1) * MAP_SIZE + col + 1] == color)
    {
        row--;
        col++;
        count++;
    }
    if (count == WIN_LEN)
        return true;
    else
        return false;
}
